package com.hjw.filters;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.hjw.constants.TokenConstants;
import com.hjw.util.JwtUtil;
import com.hjw.util.R;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1. 得到请求
        ServerHttpRequest request = exchange.getRequest();
        //2. 放行白名单
        String path = request.getURI().getPath();
        log.info("path:{}",path);
        //3. 获取请求头中的authrization请求头的值
        String header = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
        //4. 判断是否为空
        if(StrUtil.isBlank(header)){
            log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
            return webFluxResponseWriter(exchange,"认证不成功！", HttpStatus.UNAUTHORIZED.value());
        }
        //5. 开始解析
        String token = getToken(header);
        Claims claims = JwtUtil.parseToken(token);
        if(claims == null){     // 如果解析出的结果为null，证明前端携带的请求头中的token是错误的
            log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
            return webFluxResponseWriter(exchange,"Token信息丢失或无效！", HttpStatus.UNAUTHORIZED.value());
        }
        //6. 得到claims当前放入的token值(当时生成的uuid)
        String uuidToken = (String) claims.get(TokenConstants.JWT_TOKEN);
        //6.1 拼装redis的key
        String redisKey = getRedisKey(uuidToken);
//        6.2 判断redis中是否在此key
        if(StrUtil.isBlank(redisKey) || !redisTemplate.hasKey(redisKey)){
            log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
            return webFluxResponseWriter(exchange,"登录信息错误，请稍后重试！", HttpStatus.UNAUTHORIZED.value());
        }
        return chain.filter(exchange);
    }
    //2. 返回路径匹配器是否匹配成功
    private boolean pathMatcher(String path, List<String> whiteList) {
        for (String s : whiteList) {
            return path.contains(s);
        }
        return false;
    }

    //2. 获到redis的key
    private String getRedisKey(String uuidToken) {
        return TokenConstants.REDIS_PREFIX + uuidToken;
    }

    //2. 从请求头中得到token值
    private String getToken(String header) {
        if(header.startsWith("Bearer ")){
            String token = header.replaceAll(TokenConstants.PREFIX, "");
            return token;
        }
        return null;
    }

    //2. 定义将指定的信息输出到页面中
    private Mono<Void> webFluxResponseWriter(ServerWebExchange exchange, String msg, int code) {
        ServerHttpResponse response = exchange.getResponse();
        R fail = R.fail(code, msg);
        DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(fail).getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}